package com.pxmeta.party.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.pxmeta.chat.service.HuanxinService;
import com.pxmeta.common.constant.Status;
import com.pxmeta.common.exception.ServiceException;
import com.pxmeta.common.utils.ThreadPoolExecutorUtil;
import com.pxmeta.order.service.IOrderService;
import com.pxmeta.party.entity.*;
import com.pxmeta.party.entity.dto.AddGiftDTO;
import com.pxmeta.party.entity.dto.GiveLotteryGiftDTO;
import com.pxmeta.party.entity.dto.UpdateGiftDTO;
import com.pxmeta.party.entity.vo.GiftLotteryVO;
import com.pxmeta.party.entity.vo.LotteryGiftVO;
import com.pxmeta.party.entity.LotteryLuckyUser;
import com.pxmeta.party.entity.vo.TurntableLotteryVO;
import com.pxmeta.party.entity.vo.WormholeLotteryVO;
import com.pxmeta.party.mapper.GiftMapper;
import com.pxmeta.party.service.*;
import com.pxmeta.user.entity.*;
import com.pxmeta.user.entity.vo.UserVO;
import com.pxmeta.user.service.IUserBillService;
import com.pxmeta.user.service.IUserRankService;
import com.pxmeta.user.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.CollectionUtil;
import org.apache.commons.compress.utils.Lists;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.glassfish.jersey.internal.guava.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 语聊派对表 服务实现类
 * </p>
 *
 * @author wcl
 * @since 2022-06-25
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class GiftServiceImpl extends ServiceImpl<GiftMapper, Gift> implements IGiftService {
    private final IUserBillService userBillService;
    private final IUserService userService;
    private final IAssociationUserService associationUserService;
    private final IAssociationService associationService;
    private final IPartyGiveGiftService partyGiveGiftService;
    private final IGiftLotteryService giftLotteryService;

    private final IUserWormholeService userWormholeService;

    private final ILotteryOpenService lotteryOpenService;

    @Autowired
    private  IUserGiftWallService userGiftWallService;

    @Autowired
    private HuanxinService huanxinService;

    private final IUserRankService userRankService;

    @Autowired
    private IPartyService partyService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private ILotteryLuckyUserService lotteryLuckyUserService;
    @Autowired
    private ITurntableNumberService turntableNumberService;

    @Autowired
    private IUserTurntableNumberService userTurntableNumberService;

    private final IUserGiftService userGiftService;


    private static final int WEIGHT_MULTIPLIER = 10000; // Adjust this multiplier as needed

    @Override
    public IPage<Gift> getGiftProbability(Integer page, Integer size, Integer type) {
        LambdaQueryWrapper<Gift> wrapper = Wrappers.lambdaQuery();
        if (type !=null ){
            wrapper.eq(Gift::getType,type);
        }
        wrapper.eq(Gift::getStatus, Status.SUCCESS.getValue())
                .orderByAsc(Gift::getPrice);
        Page<Gift> pageResult = this.page(new Page<>(page, size), wrapper);
        if (type != null && type != 1){
            List<GiftLotteryVO> rewardList = Lists.newArrayList();
            if (type == 3){
                rewardList = this.getRewardList(1000, Boolean.TRUE);
            }
            if (type == 4){
                rewardList = this.getRewardList(2000, Boolean.TRUE);
            }
            if (type == 5){
                rewardList = this.getRewardList(3000, Boolean.TRUE);
            }
            for (Gift record : pageResult.getRecords()) {
                for (GiftLotteryVO vo : rewardList) {
                    if (record.getId().equals(vo.getRewardGiftId())){
                        record.setProbability(vo.getProbability().doubleValue());
                        record.setCount(vo.getCount());
                        record.setRemainingQuantity(vo.getRemainingQuantity());
                        record.setConditionCount(vo.getConditionCount());
                        break;
                    }
                }
            }
        }
        return pageResult;
    }


    @Override
    public IPage<Gift> getGiftList(Integer page, Integer size, Integer type) {
        LambdaQueryWrapper<Gift> wrapper = Wrappers.lambdaQuery();
        if (type !=null ){
            wrapper.eq(Gift::getType,type);
        }
        wrapper.eq(Gift::getStatus, Status.SUCCESS.getValue())
                .orderByAsc(Gift::getPrice);
        return this.page(new Page<>(page, size),wrapper);
    }

    @Override
    public List<Gift> getAllGiftList() {
        LambdaQueryWrapper<Gift> wrapper = Wrappers.lambdaQuery();
        wrapper.ne(Gift::getType, 2)
                .orderByAsc(Gift::getPrice);
        return this.list(wrapper);
    }


    /**
     * 发送全服通知
     */
    public void sendFullServerNotification(String text){

        List<User> allUsers = userService.list();

        List<List<User>> partition = CollectionUtil.partition(allUsers, 100);

        for (List<User> users : partition) {
            List<String> usernames = users.stream().map(User::getUsername).collect(Collectors.toList());

            List<User> onlineUsers = Lists.newArrayList();

            JSONArray statusList = huanxinService.batchUserStatus(usernames);
            //处理用户在线状态
            for (Object obj : statusList) {
                String str = JSONObject.toJSONString(obj);
                JSONObject jsonObject = JSONObject.parseObject(str);
                Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();
                for (Map.Entry<String, Object> entry : entries) {
                    Optional<User> opt = users.stream().filter(u -> u.getUsername().equals(entry.getKey())).findFirst();
                    if (opt.isPresent() && opt.get().getUsername().equals(entry.getKey()) && "online".equals(entry.getValue())) {
                        onlineUsers.add(opt.get());
                        break;
                    }
                }
            }
            if (onlineUsers.isEmpty()){
                return;
            }
            //发送全服通知
            huanxinService.sendTransparentMsg(onlineUsers.stream().map(User::getUsername).collect(Collectors.toList()),text);
        }

    }


    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void give(Long userId, Long targetUsername, Integer giftId, Long partyId, Integer type, Integer giftCount) {
        Party party = partyService.getById(partyId);
        User targetUser = userService.getByUsername(targetUsername.toString());
        Long targetUserId = targetUser.getId();
        double rate = 1; //默认分成比例为65%;
//        if (party.getType()==6){
//            rate = 0.65;
//        }

        User user = userService.getById(userId);

        log.info("礼物id：{}",giftId);
        //获取礼物
        Gift gift = this.getById(giftId);
        Integer giftPrice = gift.getPrice();

        //礼物价值大于1000元，全站飘屏
        if (giftPrice>=100000){
            Runnable task = () -> {
                String msg = String.format("%s对%s送出%s×%s",user.getNickname(),targetUser.getNickname(),gift.getName(),giftCount);
                sendFullServerNotification(msg);
            };
            ThreadPoolExecutorUtil.submit(task);
        }

        giftPrice = giftCount * giftPrice;

        partyGiveGiftService.saveRecord(partyId, userId, targetUserId, giftId, giftCount, giftPrice);

        if (type != null && type == 1){
            //抽奖
            LambdaQueryWrapper<UserGift> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(UserGift::getGiftId, giftId)
                    .eq(UserGift::getUserId, userId);
            userGiftService.getOne(wrapper);

            UserGift userGift = userGiftService.getOne(wrapper);
            Integer count = userGift.getCount();
            count -= giftCount;
            if (count < 0){
                throw new ServiceException("礼物数量不足！");
            }
            userGift.setCount(count);
            userGiftService.updateById(userGift);
        }else {
            //扣减当前用户余额
            if (type != null && type == 3){
                Gift treasureChestGift = giftLotteryService.getTreasureChestByRewardGiftId(giftId);
                Integer chestGiftPrice = treasureChestGift.getPrice();
                chestGiftPrice = giftCount * chestGiftPrice;
                userService.subBalance(userId, BigDecimal.valueOf(chestGiftPrice));
            }else{
                if (type != null && type == 10){
                    rate = 0.04;
                }else {
                    userService.subBalance(userId, BigDecimal.valueOf(giftPrice));
                }
            }
        }
        Long associationId = party.getAssociationId(); //房间公会id

        //增加消费等级
        userRankService.addNobleExp(userId,giftPrice);
        //增加人气等级
        userRankService.addCharmExp(targetUserId,giftPrice);
        //记录礼物墙
        userGiftWallService.addUserGiftWall(targetUserId,giftId,giftCount);

        //记录支出
        UserBill userBill = new UserBill();
        userBill.setStatus(Status.SUCCESS.getValue());
        userBill.setUserId(userId);
        userBill.setTargetId(targetUserId);
        userBill.setPm(0);
        userBill.setCategory(UserBillCategoryEnum.BALANCE.getCategory());
        userBill.setType(UserBillTypeEnum.PARTY_GIFT.getType());
        userBill.setNumber(BigDecimal.valueOf(giftPrice*rate));

        userBill.setPartyId(partyId);
        userBill.setDescription(String.format("赠送礼物给用户%s 「%s」「%s」成功",user.getAccount(), user.getNickname(), gift.getName()));
        userBillService.save(userBill);

        //记录收益
        UserBill targetUserBill = new UserBill();
        targetUserBill.setStatus(Status.SUCCESS.getValue()); //状态是否要变为审核中？
        targetUserBill.setUserId(targetUserId);
        targetUserBill.setTargetId(userId);
        targetUserBill.setPm(1);
        targetUserBill.setPartyId(partyId);
        targetUserBill.setType(UserBillTypeEnum.PARTY_GIFT.getType());
        targetUserBill.setCategory(UserBillCategoryEnum.PROFIT.getCategory());
        //计算去除分成后的收益金额
        BigDecimal number = BigDecimal.valueOf((double)giftPrice/100)
                .multiply(BigDecimal.valueOf(rate)).setScale(2, RoundingMode.HALF_UP);

        targetUserBill.setNumber(number);

        targetUserBill.setDescription(String.format("在派对房收到用户%s「%s」的礼物「%s」",targetUser.getAccount(),targetUser.getNickname(),gift.getName()));
        userBillService.save(targetUserBill);


//        userService.increaseProfit(targetUserId, number);

        //查询该用户的工会，根据分成比例记账。
        if (null != associationId){
            //查询当前签约的公会的分成比例，记录流水时，记录到公会账下。
            Association association = associationService.getById(associationId);
            double commissionRatio = association.getCommissionRatio().doubleValue();
//            //如果送给厅主，则不计入。
//            if (party.getUserId().equals(targetUserId)){
//                return;
//            }

            AssociationUser associationUser = associationUserService.getUserSign(user.getId());
            Long presidentUserId = association.getPresidentUserId(); //房间厅主id
            //记录收益
            UserBill presidentBill = new UserBill();
            presidentBill.setStatus(Status.SUCCESS.getValue());
            presidentBill.setUserId(presidentUserId);
            presidentBill.setTargetId(userId);
            presidentBill.setPm(1);
            presidentBill.setPartyId(partyId);
            presidentBill.setType(UserBillTypeEnum.PARTY_GIFT.getType());
            presidentBill.setCategory(UserBillCategoryEnum.PROFIT.getCategory());
            //计算去除分成后的收益金额
            BigDecimal presidentNumber = BigDecimal.valueOf((double)giftPrice/100)
                    .multiply(BigDecimal.valueOf(commissionRatio)).setScale(2, RoundingMode.HALF_UP);
            presidentBill.setNumber(presidentNumber);
            presidentBill.setDescription(String.format("主播「%s」在派对房收到礼物「%s」",targetUser.getNickname(),gift.getName()));
            userBillService.save(presidentBill);

            //收益记到房主号。
//            userService.increaseProfit(presidentUserId, presidentNumber);

            if (associationUser != null){
                BigDecimal totalEarnings = associationUser.getTotalEarnings();
                BigDecimal weekEarnings = associationUser.getWeekEarnings();
                associationUser.setTotalEarnings(totalEarnings.add(targetUserBill.getNumber()).add(presidentNumber));
                associationUser.setWeekEarnings(weekEarnings.add(targetUserBill.getNumber()).add(presidentNumber));
                associationUserService.updateById(associationUser);
            }
        }

        if (type != null && type == 10){
            return;
        }
//        //小清新客户代码。用户刷礼物后给上级返3%收益
//        User currentUser = userService.getById(userId);
//        Long parentUserId = currentUser.getParentUserId();
//        if (parentUserId !=null){
//            BigDecimal value = number.multiply(BigDecimal.valueOf(0.03)).setScale(2, RoundingMode.HALF_UP);
//            userService.increaseProfit(parentUserId,value);
//            UserBill shareBill = new UserBill();
//            shareBill.setDescription(String.format("下级刷礼物返积分：%s", number));
//            shareBill.setUserId(parentUserId);
//            shareBill.setTargetId(userId);
//            shareBill.setCategory(UserBillCategoryEnum.PROFIT.getCategory());
//            shareBill.setPm(1);
//            shareBill.setNumber(value);
//            shareBill.setType(UserBillTypeEnum.SHARE.getType());
//            shareBill.setStatus(Status.SUCCESS.getValue());
//            userBillService.save(shareBill);
//        }

    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void give(Long userId, List<String> targetUsernames, Integer giftId, Long partyId, Integer type, Integer count) {
        for (String targetUsername : targetUsernames) {
            if (StringUtils.isNotBlank(targetUsername)){
                this.give(userId, Long.parseLong(targetUsername), giftId, partyId, type,count);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public List<LotteryGiftVO> lottery(Long userId, Integer giftId, List<String> targetUsernames, Long partyId) {
        List<UserVO> users = userService.getUsersByUsernames(targetUsernames);
        User currentUser = userService.getById(userId);
        Gift gift = this.getById(giftId);
        if (null == gift){
            throw new ServiceException("礼物不存在！");
        }

        int totalPrice = users.size() * gift.getPrice();
        List<GiftLotteryVO> list = this.getRewardList(giftId, Boolean.TRUE);

        int totalCount = 0;
        for (GiftLotteryVO vo : list) {
            Integer remainingQuantity = vo.getRemainingQuantity();
            totalCount += remainingQuantity;
        }

        List<LotteryGiftVO> finalList = Lists.newArrayList();

        int type = 3;
        if (gift.getPrice() == 30){
            type = 3;
        }
        if (gift.getPrice() == 100){
            type = 4;
        }
        if (gift.getPrice() == 200){
            type = 5;
        }
        TurntableNumber turntableNumber = turntableNumberService.getTurntableNumber(type);

        //判断总奖池是否亏损
        if (totalCount<=0){
//            turntableNumberService.removeById(turntableNumber);
//            turntableNumber = new TurntableNumber();
            turntableNumber.setGiftNumber(BigDecimal.ZERO);
            turntableNumber.setType(type);
            turntableNumber.setConsumeNumber(BigDecimal.ZERO);
            turntableNumber.setLotteryCount(users.size());
            turntableNumberService.updateById(turntableNumber);

            List<GiftLottery> updateCountList = Lists.newArrayList();
            for (GiftLotteryVO vo : list) {
                GiftLottery giftLottery = new GiftLottery();
                giftLottery.setId(vo.getId());
                giftLottery.setRemainingQuantity(vo.getCount());
                totalCount+=giftLottery.getRemainingQuantity();
                vo.setRemainingQuantity(vo.getCount());
                updateCountList.add(giftLottery);
            }
            giftLotteryService.updateBatchById(updateCountList);
        }
        list = list.stream().filter(l->l.getRemainingQuantity()>0 && l.getConditionCount()<= turntableNumber.getLotteryCount()).collect(Collectors.toList());


        UserTurntableNumber userTurntableNumber = userTurntableNumberService.getUserTurntableNumber(userId, type);
        Integer nextWinGift = userTurntableNumber.getNextWinGift();

        if (nextWinGift != null){
            userTurntableNumberService.update(userTurntableNumber,Wrappers.<UserTurntableNumber>lambdaUpdate()
                    .set(UserTurntableNumber::getNextWinGift,null)
                    .eq(UserTurntableNumber::getId, userTurntableNumber.getId()));
        }

        int idx = 0;

        List<LotteryLuckyUser> luckyUsers = Lists.newArrayList();
        long recordId = IdWorker.getId();

        List<GiftLottery> giftLotteries = Lists.newArrayList();

        for (UserVO user : users) {
            //抽奖
            HashMap<GiftLotteryVO, Double> map = Maps.newHashMap();
            for (GiftLotteryVO vo : list) {
                map.put(vo,(double) vo.getRemainingQuantity()/totalCount);
            }
            GiftLotteryVO vo = weightRandom(map);

            //减少剩余数量
            Integer remainingQuantity = vo.getRemainingQuantity();
            remainingQuantity--;

            if (remainingQuantity <=0){
                list.remove(vo);
            }

            vo.setRemainingQuantity(remainingQuantity);

            GiftLottery giftLottery = new GiftLottery();
            giftLottery.setId(vo.getId());
            giftLottery.setRemainingQuantity(vo.getRemainingQuantity());
            giftLotteries.add(giftLottery);


            if (nextWinGift != null && idx == 0){
                Optional<GiftLotteryVO> first = list.stream().filter(l -> l.getRewardGiftId().equals(nextWinGift)).findFirst();
                if (first.isPresent()){
                    vo = first.get();
                }
            }
            idx++;

            LotteryGiftVO lotteryGiftVO = new LotteryGiftVO();
            lotteryGiftVO.setTargetUser(user);
            lotteryGiftVO.setIcon(vo.getIcon());
            lotteryGiftVO.setName(vo.getName());
            lotteryGiftVO.setMaterialUrl(vo.getMaterialUrl());
            lotteryGiftVO.setPrice(vo.getPrice());
            lotteryGiftVO.setId(vo.getRewardGiftId());
            finalList.add(lotteryGiftVO);

            //保存中奖记录
            LotteryLuckyUser lotteryLuckyUser = new LotteryLuckyUser();
            lotteryLuckyUser.setUserId(userId);
            lotteryLuckyUser.setRecordId(recordId);
            lotteryLuckyUser.setConsumePrice((double)totalPrice);
            lotteryLuckyUser.setGiftId(vo.getRewardGiftId());
            lotteryLuckyUser.setCount(1);
            lotteryLuckyUser.setType(type);
            lotteryLuckyUser.setNickname(user.getNickname());
            lotteryLuckyUser.setPrice(vo.getPrice());
            lotteryLuckyUser.setAvatar(user.getAvatar());
            lotteryLuckyUser.setContent(currentUser.getNickname()+"抽中"+ gift.getName() + "×"+1);
            luckyUsers.add(lotteryLuckyUser);
            this.give(userId,Long.parseLong(user.getUsername()),vo.getRewardGiftId(),partyId,3,1);
        }
        if (!luckyUsers.isEmpty()){
            lotteryLuckyUserService.saveBatch(luckyUsers);
        }

        if (!giftLotteries.isEmpty()){
            giftLotteryService.updateBatchById(giftLotteries);
        }

        turntableNumber.setLotteryCount(turntableNumber.getLotteryCount()+targetUsernames.size());
        turntableNumber.setTotalCycleCount(totalCount);
        int sum = finalList.stream().mapToInt(LotteryGiftVO::getPrice).sum();
        turntableNumber.setGiftNumber(turntableNumber.getGiftNumber().add(BigDecimal.valueOf(sum)));
        turntableNumber.setConsumeNumber(turntableNumber.getConsumeNumber().add(BigDecimal.valueOf(totalPrice)));
        turntableNumberService.updateById(turntableNumber);

        return finalList;
    }

    @Override
    public List<Gift> getTurntableGiftList(Integer type) {
        LambdaQueryWrapper<Gift> wrapper = Wrappers.lambdaQuery();

        if (type == 2){
            wrapper.eq(Gift::getType,3);
        }else {
            wrapper.eq(Gift::getType,4);
        }
        wrapper.orderByAsc(Gift::getSort);
        return this.list(wrapper);
    }



    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public List<TurntableLotteryVO> turntableLottery(Long userId,Integer count, Integer type) {

        Double price = 0d;
        if (type == 1){
            price = 10.0;
            if (count == 10){
                price = 95.0;
            }
        }else if (type == 2){
            price = 50.0;
            if (count == 10){
                price = 490.0;
            }
        }

        userService.subBalance(userId,BigDecimal.valueOf(price));
        List<TurntableLotteryVO> finalList = Lists.newArrayList();

        //查询公共池
        TurntableNumber turntableNumber = turntableNumberService.getTurntableNumber(type);

        //查询个人池
        UserTurntableNumber userTurntableNumber = userTurntableNumberService.getUserTurntableNumber(userId, type);
        Integer nextWinGiftId = userTurntableNumber.getNextWinGift();


        log.info("开始转盘，查询是否有补发的礼物，补发礼物id:{}", nextWinGiftId);
        Boolean flag = Boolean.TRUE;


        List<GiftLotteryVO> list = Lists.newArrayList();
        if (type == 1){
            list = getRewardList(2000, flag);

        }else if (type ==2 ){
            list = getRewardList(1000, flag);
        }

        int totalCount = 0;
        for (GiftLotteryVO vo : list) {
            Integer remainingQuantity = vo.getRemainingQuantity();
            totalCount += remainingQuantity;
        }

        //判断总奖池是否亏损
        if (totalCount<count){
            turntableNumberService.removeById(turntableNumber);
            turntableNumber = new TurntableNumber();
            turntableNumber.setGiftNumber(BigDecimal.ZERO);
            turntableNumber.setType(type);
            turntableNumber.setConsumeNumber(BigDecimal.ZERO);
            turntableNumber.setLotteryCount(count);
            turntableNumberService.save(turntableNumber);

            List<GiftLottery> updateCountList = Lists.newArrayList();
            for (GiftLotteryVO vo : list) {
                GiftLottery giftLottery = new GiftLottery();
                giftLottery.setId(vo.getId());
                vo.setRemainingQuantity(vo.getRemainingQuantity()+vo.getCount());
                giftLottery.setRemainingQuantity(vo.getRemainingQuantity()+vo.getCount());
                totalCount += giftLottery.getRemainingQuantity();
                updateCountList.add(giftLottery);
            }
            giftLotteryService.updateBatchById(updateCountList);
        }

        //移除已经数量不足的礼物
        TurntableNumber finalTurntableNumber = turntableNumber;
        List<GiftLotteryVO> list1 = list;
        list = list.stream().filter(l->l.getRemainingQuantity()>0 && l.getConditionCount()<= finalTurntableNumber.getLotteryCount()).collect(Collectors.toList());

//        //获取当前奖池中最小的礼物。
//        GiftLotteryVO minVo = list.stream()
//                .min(Comparator.comparingInt(GiftLotteryVO::getPrice))
//                .orElse(null);

//        //0-5次，20-23次，50-55次， 80-90次会很白. 移除掉最小的礼物。
        Integer userTurntableNumberCount = userTurntableNumber.getCount();

        List<GiftLotteryVO> giftList = Lists.newArrayList();
        for (GiftLotteryVO vo : list) {

        }

        List<GiftLottery> giftLotteries = Lists.newArrayList();
        for (int i = 0; i < count; i++) {
            HashMap<GiftLotteryVO, Double> map = Maps.newHashMap();
            for (GiftLotteryVO vo : list) {
                map.put(vo,(double) vo.getRemainingQuantity()/totalCount);
            }

            GiftLotteryVO vo = weightRandom(map);

            //减少剩余数量
            Integer remainingQuantity = vo.getRemainingQuantity();
            remainingQuantity--;

            vo.setRemainingQuantity(remainingQuantity);
            if (remainingQuantity <=0){
                list.remove(vo);
            }
            GiftLottery giftLottery = new GiftLottery();
            giftLottery.setId(vo.getId());
            giftLottery.setRemainingQuantity(vo.getRemainingQuantity());
            giftLotteries.add(giftLottery);

            if (nextWinGiftId != null&& i==0){

                log.info("礼物补发开始：补发id:{}", nextWinGiftId);
                Optional<GiftLotteryVO> opt = list1.stream().filter(l -> l.getRewardGiftId().equals(nextWinGiftId)).findFirst();
                if (opt.isPresent()){
                    log.info("礼物补发成功：补发id:{}", nextWinGiftId);
                    giftList.add(opt.get());
                }else {
                    giftList.add(vo);
                }
                continue;
            }

            giftList.add(vo);
        }

        if (!giftLotteries.isEmpty()){
            giftLotteryService.updateBatchById(giftLotteries);
        }

        User user = userService.getById(userId);
        String nickname = user.getNickname();
        String finalNickname = "";
        if (StringUtils.isNotBlank(nickname)){
            char lastStr = nickname.charAt(nickname.length() - 1);
            finalNickname = "****"+lastStr;
        }

        // 对抽到的奖品进行分组并获取数量
        Map<GiftLotteryVO, Integer> giftCounts = new HashMap<>();
        for (GiftLotteryVO vo : giftList) {
            giftCounts.put(vo, giftCounts.getOrDefault(vo, 0) + 1);
        }
        long id = IdWorker.getId();
        // 现在，giftCounts中包含了每种奖品及其对应的数量


        //记录公池和个池。
        userTurntableNumber.setCount(userTurntableNumberCount+1);
        userTurntableNumber.setLotteryCount(userTurntableNumberCount + count);
        userTurntableNumber.setConsumeNumber(userTurntableNumber.getConsumeNumber().add(BigDecimal.valueOf(price)));
        turntableNumber.setLotteryCount(turntableNumber.getLotteryCount()+count);
        turntableNumber.setConsumeNumber(turntableNumber.getConsumeNumber().add(BigDecimal.valueOf(price)));
        turntableNumber.setTotalCycleCount(totalCount);
        double giftPrice = 0d;

        List<LotteryLuckyUser> lotteryLuckyUsers = Lists.newArrayList();
        for (Map.Entry<GiftLotteryVO, Integer> entry : giftCounts.entrySet()) {
            GiftLotteryVO gift = entry.getKey();
            Integer quantity = entry.getValue();
            TurntableLotteryVO vo = new TurntableLotteryVO();

            double currentPrice = gift.getPrice().doubleValue() * quantity;
            //如果获得该礼物后，平台亏损，给用户返回一个最低价格礼物。

//            if (nextWinGiftId == null){
//                if ((currentPrice + giftPrice + turntableNumber.getGiftNumber().doubleValue())
//                        >turntableNumber.getConsumeNumber().doubleValue()){
//                    gift = minVo;
//                    //重置价格
//                    currentPrice = gift.getPrice().doubleValue() * quantity;
//                }
//            }

            vo.setGift(gift);
            giftPrice += currentPrice;
            vo.setCount(quantity);
            finalList.add(vo);
            //保存中奖记录
            LotteryLuckyUser lotteryLuckyUser = new LotteryLuckyUser();
            lotteryLuckyUser.setUserId(userId);
            lotteryLuckyUser.setRecordId(id);
            lotteryLuckyUser.setConsumePrice(price);
            lotteryLuckyUser.setGiftId(gift.getRewardGiftId());
            lotteryLuckyUser.setCount(quantity);
            lotteryLuckyUser.setType(type);
            lotteryLuckyUser.setNickname(user.getNickname());
            lotteryLuckyUser.setPrice(gift.getPrice());
            lotteryLuckyUser.setAvatar(user.getAvatar());
            lotteryLuckyUser.setContent(finalNickname+"抽中"+ gift.getName() + "×"+quantity);
            lotteryLuckyUsers.add(lotteryLuckyUser);

        }

        this.saveGift(lotteryLuckyUsers, userId);


        if (!lotteryLuckyUsers.isEmpty()){
            lotteryLuckyUserService.saveBatch(lotteryLuckyUsers);
        }

        turntableNumber.setGiftNumber(turntableNumber.getGiftNumber().add(BigDecimal.valueOf(giftPrice)));
        userTurntableNumber.setGiftNumber(userTurntableNumber.getGiftNumber().add(BigDecimal.valueOf(giftPrice)));
        userTurntableNumberService.updateById(userTurntableNumber);
        turntableNumberService.updateById(turntableNumber);
        // 最后返回抽到的奖品列表

        if (nextWinGiftId != null){
            userTurntableNumberService.update(userTurntableNumber,Wrappers.<UserTurntableNumber>lambdaUpdate()
                    .set(UserTurntableNumber::getNextWinGift,null)
                    .eq(UserTurntableNumber::getId, userTurntableNumber.getId()));
        }

        return finalList;
    }

    public void saveGift(List<LotteryLuckyUser> lotteryLuckyUsers, Long userId){
        List<Integer> giftIds = lotteryLuckyUsers.stream().map(LotteryLuckyUser::getGiftId).collect(Collectors.toList());

        //保存到背包
        if (!giftIds.isEmpty()){
            LambdaQueryWrapper<UserGift> wrapper = Wrappers.lambdaQuery();
            wrapper.in(UserGift::getGiftId, giftIds)
                    .eq(UserGift::getUserId, userId);

            List<UserGift> userGifts = userGiftService.list(wrapper);

            List<UserGift> updateList = Lists.newArrayList();

            List<UserGift> saveList = Lists.newArrayList();

            for (LotteryLuckyUser lotteryLuckyUser : lotteryLuckyUsers) {
                Optional<UserGift> opt = userGifts.stream().filter(ug -> ug.getGiftId().equals(lotteryLuckyUser.getGiftId())).findFirst();
                if (opt.isPresent()){
                    //有礼物，更新。
                    UserGift userGift = opt.get();
                    userGift.setCount(userGift.getCount() + lotteryLuckyUser.getCount());
                    updateList.add(userGift);
                }else {
                    UserGift ug = new UserGift();
                    ug.setGiftId(lotteryLuckyUser.getGiftId());
                    ug.setUserId(userId);
                    ug.setCount(lotteryLuckyUser.getCount());
                    saveList.add(ug);
                }
            }

            if (!saveList.isEmpty()){
                userGiftService.saveBatch(saveList);
            }
            if (!updateList.isEmpty()){
                userGiftService.updateBatchById(updateList);
            }
        }
    }
    @Override
    public List<Gift> getUserGiftList(Long userId) {
        LambdaQueryWrapper<UserGift> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserGift::getUserId, userId)
                .ne(UserGift::getCount, 0);
        List<UserGift> list = userGiftService.list(wrapper);
        List<Integer> giftIds = list.stream().map(UserGift::getGiftId).collect(Collectors.toList());
        if (giftIds.isEmpty()){
            return com.google.common.collect.Lists.newLinkedList();
        }

        List<Gift> gifts = this.listByIds(giftIds);

        for (Gift gift : gifts) {
            Optional<UserGift> first = list.stream().filter(l -> l.getGiftId().equals(gift.getId())).findFirst();
            if (first.isPresent()){
                UserGift userGift = first.get();
                gift.setCount(userGift.getCount());
            }
        }

        return gifts;
    }

    @Override
    public Boolean checkIsOpenLottery(Long userId) {
        //用户充值到 100 元后，才可以开启。
        UserRank userRank = userRankService.getById(userId);
        LotteryOpen lotteryOpen = lotteryOpenService.getById(1);
        if (lotteryOpen == null || !lotteryOpen.getIsOpen()){
            return Boolean.FALSE;
        }
        if (userRank != null && userRank.getNobleRank()>=lotteryOpen.getRankValue()){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;

    }

    /**
     * 添加礼物
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void addGift(AddGiftDTO dto) {

        Integer crateGiftId = dto.getCrateGiftId();
        Gift gift = new Gift();
        gift.setIcon(dto.getIcon());
        gift.setName(dto.getName());
        gift.setPrice(dto.getPrice());

        if (crateGiftId != null){
            gift.setType(6);//盲盒中的奖品
        }else {
            gift.setType(dto.getType());
        }
        gift.setStatus(dto.getStatus()?1:0);
        gift.setMaterialUrl(dto.getMaterialUrl());
        gift.setIsTreasure(dto.getIsTreasure());
        this.save(gift);

        if (crateGiftId != null){
            //概率
            Double probability = dto.getProbability();
            GiftLottery gl = new GiftLottery();
            gl.setProbability(BigDecimal.valueOf(probability));
            gl.setGiftId(crateGiftId);
            gl.setIsProfit(Boolean.TRUE);
            gl.setRewardGiftId(gift.getId());
            giftLotteryService.save(gl);
        }
    }


    @Override
    public List<GiftLotteryVO> getRewardList(Integer giftId, Boolean isProfit) {
        LambdaQueryWrapper<GiftLottery> wrapper = Wrappers.lambdaQuery();
        if (giftId == 9999){
            LambdaQueryWrapper<Gift> giftWrapper = Wrappers.lambdaQuery();
            giftWrapper.eq(Gift::getIsTreasure,Boolean.TRUE);
            List<Integer> giftIds = this.list(giftWrapper).stream().map(Gift::getId).collect(Collectors.toList());
            if (!giftIds.isEmpty()){
                wrapper.in(GiftLottery::getGiftId, giftIds);
            }
        }else {
            wrapper.eq(GiftLottery::getGiftId,giftId);
        }


        wrapper.eq(GiftLottery::getIsProfit, Boolean.TRUE);

        List<GiftLottery> list = giftLotteryService.list(wrapper);
        if (list.isEmpty()){
            return Lists.newArrayList();
        }
        List<Integer> rewardGiftIds = list.stream().map(GiftLottery::getRewardGiftId).collect(Collectors.toList());

        List<Gift> gifts = this.listByIds(rewardGiftIds);

        List<GiftLotteryVO> finalList = Lists.newArrayList();
        for (GiftLottery giftLottery : list) {
            GiftLotteryVO vo = new GiftLotteryVO();
            vo.setId(giftLottery.getId());
            vo.setGiftId(giftLottery.getGiftId());
            vo.setRewardGiftId(giftLottery.getRewardGiftId());
            Optional<Gift> first = gifts.stream().filter(g -> g.getId().equals(giftLottery.getRewardGiftId())).findFirst();
            if (first.isPresent()){
                Gift gift = first.get();
                vo.setIcon(gift.getIcon());
                vo.setName(gift.getName());
                vo.setPrice(gift.getPrice());
                vo.setMaterialUrl(gift.getMaterialUrl());
            }
            vo.setConditionCount(giftLottery.getConditionCount());
            vo.setCount(giftLottery.getCount());
            vo.setRemainingQuantity(giftLottery.getRemainingQuantity());
            vo.setProbability(giftLottery.getProbability());
            finalList.add(vo);
        }

        return finalList;

    }

    @Override
    public void startWormhole(Long userId, Integer count) {

        int price = count * 10;
        TurntableNumber turntableWormhole = turntableNumberService.getTurntableWormhole();
        turntableWormhole.setConsumeNumber(turntableWormhole.getConsumeNumber().add(BigDecimal.valueOf(price)));
        turntableNumberService.updateById(turntableWormhole);

        //扣减余额
        userService.subBalance(userId, price);

        LambdaQueryWrapper<UserWormhole> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserWormhole::getUserId, userId);
        //删除
        userWormholeService.remove(wrapper);
        //初始化倍率
        UserWormhole userWormhole = new UserWormhole();
        userWormhole.setCount(count);
        userWormhole.setUserId(userId);
        userWormhole.setMagnification(1);
        userWormholeService.save(userWormhole);
    }

    @Override
    public WormholeLotteryVO nextWormhole(Long userId, Integer count) {
        LambdaQueryWrapper<UserWormhole> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserWormhole::getUserId, userId);


        UserWormhole userWormhole = userWormholeService.getOne(wrapper);
        if (userWormhole == null){
            throw new ServiceException("参数错误！");
        }
        //获取概率
        double rate = BigDecimal.valueOf((double) 1/count).setScale(2,RoundingMode.HALF_UP).doubleValue();

        //创建两个奖品实例，一个中奖，一个不中奖
        WormholeLotteryVO vo1 = new WormholeLotteryVO();
        vo1.setWormholeId(userWormhole.getId());
        vo1.setIsSuccess(Boolean.TRUE);


        WormholeLotteryVO vo2 = new WormholeLotteryVO();
        vo2.setWormholeId(userWormhole.getId());
        vo2.setIsSuccess(Boolean.FALSE);

        List<WormholeLotteryVO> list = Lists.newArrayList();
        list.add(vo1);
        list.add(vo2);
        Map<WormholeLotteryVO, Double> map = Maps.newHashMap();
        for (WormholeLotteryVO vo : list) {
            if (vo.getIsSuccess()){
                map.put(vo,rate);
            }else {
                map.put(vo, 1-rate);
            }
        }

        WormholeLotteryVO vo = weightRandomWormhole(map);//抽奖获取奖励

        TurntableNumber turntableWormhole = turntableNumberService.getTurntableWormhole();
        if (turntableWormhole.getGiftNumber().doubleValue()>turntableWormhole.getConsumeNumber().doubleValue()){
            //平台开始亏钱，让用户亏
            vo = vo2;
        }
        Integer magnification = userWormhole.getMagnification();
        if (vo.getIsSuccess()){

            magnification = magnification * count;

            if (magnification >= 512){
                magnification = 512;
                vo.setIsPass(Boolean.TRUE);
            }
        }else {
            magnification = 0;
//            this.endWormhole(userWormhole.getId());
        }
        userWormhole.setMagnification(magnification);
        int currentCount = magnification * userWormhole.getCount();  //当前棒数量
        vo.setCurrentCount(currentCount);

        //更新记录
        userWormholeService.updateById(userWormhole);

        //随机获取下一关的虫洞数量   2-4个。
        Random random = new Random();
        int randomNumber = random.nextInt(3) + 2;
        vo.setNextCount(randomNumber);

        //计算奖励
        List<Gift> giftList = spendCoins(currentCount * 10,5,50000,10000,1000, null, 200);
        vo.setGiftList(giftList);
        return vo;
    }



    @Override
    public Boolean checkIsOpenWormhole(Long userId) {
        //判断是否可以开启虫洞
        UserRank userRank = userRankService.getById(userId);
        LotteryOpen lotteryOpen = lotteryOpenService.getById(2);
        if (lotteryOpen == null || !lotteryOpen.getIsOpen()){
            return Boolean.FALSE;
        }
        if (userRank != null && userRank.getNobleRank()>=lotteryOpen.getRankValue()){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;

    }

    @Override
    public Boolean checkIsOpenFoodStall(Long userId) {
        //判断是否可以开启吃货大排档
        UserRank userRank = userRankService.getById(userId);
        LotteryOpen lotteryOpen = lotteryOpenService.getById(3);
        if (lotteryOpen == null || !lotteryOpen.getIsOpen()){
            return Boolean.FALSE;
        }
        if (userRank != null && userRank.getNobleRank()>=lotteryOpen.getRankValue()){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;

    }


    @Override
    public Boolean checkIsOpenAdAstra(Long userId) {
        //判断是否可以开启吃货大排档
        UserRank userRank = userRankService.getById(userId);
        LotteryOpen lotteryOpen = lotteryOpenService.getById(4);
        if (lotteryOpen == null || !lotteryOpen.getIsOpen()){
            return Boolean.FALSE;
        }
        if (userRank != null && userRank.getNobleRank()>=lotteryOpen.getRankValue()){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;

    }

    @Override
    public Gift getByType(int type) {
        LambdaQueryWrapper<Gift> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Gift::getType,type);
        return this.getOne(wrapper,false);
    }

    @Override
    public List<Gift> endWormhole(Long wormholeId) {
        UserWormhole userWormhole = userWormholeService.getById(wormholeId);

        Integer magnification = userWormhole.getMagnification();

        long id = IdWorker.getId();
        //现有的金额 = 数量 * 100
        int coins = magnification * userWormhole.getCount() * 10;

        TurntableNumber turntableWormhole = turntableNumberService.getTurntableWormhole();
        turntableWormhole.setGiftNumber(turntableWormhole.getGiftNumber().add(BigDecimal.valueOf(coins)));
        turntableNumberService.updateById(turntableWormhole);


        //消耗完所有金额，奖礼物放入list中，消耗的金币优先取较大金额的，且较大金额的礼物可以重复获取。
        List<Gift> list = spendCoins(coins,5,50000,10000,1000,null, 200);
        User user = userService.getById(userWormhole.getUserId());

        if (magnification>=2){
            LotteryLuckyUser lotteryLuckyUser = new LotteryLuckyUser();
            lotteryLuckyUser.setUserId(userWormhole.getUserId());
            String nickname = user.getNickname();
            String finalNickname = "";
            if (StringUtils.isNotBlank(nickname)){
                char lastStr = nickname.charAt(nickname.length() - 1);
                finalNickname = "**"+lastStr;
            }

            lotteryLuckyUser.setRecordId(id);
            lotteryLuckyUser.setGiftId(null);
            lotteryLuckyUser.setCount(magnification);
            lotteryLuckyUser.setPrice(coins);
            lotteryLuckyUser.setNickname(user.getNickname());
            lotteryLuckyUser.setAvatar(user.getAvatar());
            lotteryLuckyUser.setContent("恭喜 "+ finalNickname + " "+ "投入"+userWormhole.getCount()+"个能量棒涨了"+magnification+"倍");
            lotteryLuckyUser.setType(0);

            lotteryLuckyUserService.save(lotteryLuckyUser);
        }

        userGiftService.addUserGift(user.getId(), list);

        userWormholeService.removeById(userWormhole);


        return list;
    }

    @Override
    public void updateGift(UpdateGiftDTO dto) {
        Gift gift = this.getById(dto.getId());
        Integer price = dto.getPrice();
        if (price != null){
            gift.setPrice(price);
        }
        if (StringUtils.isNotBlank(dto.getIcon())){
            gift.setIcon(dto.getIcon());
        }
        if (StringUtils.isNotBlank(dto.getName())){
            gift.setName(dto.getName());
        }
        this.updateById(gift);
    }

    @Override
    public List<Gift> getItemList(Integer giftId) {

        LambdaQueryWrapper<GiftLottery> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(GiftLottery::getGiftId, giftId)
                .eq(GiftLottery::getIsProfit, Boolean.TRUE);
        List<GiftLottery> list = giftLotteryService.list(wrapper);
        List<Integer> rewardGiftIds = list.stream().map(GiftLottery::getRewardGiftId).collect(Collectors.toList());
        if (rewardGiftIds.isEmpty()){
            return Lists.newArrayList();
        }
        List<Gift> gifts = this.listByIds(rewardGiftIds);
        for (Gift gift : gifts) {
            for (GiftLottery giftLottery : list) {
                if (gift.getId().equals(giftLottery.getRewardGiftId())){
                    gift.setProbability(giftLottery.getProbability().doubleValue());
                    gift.setCount(giftLottery.getCount());
                    gift.setRemainingQuantity(giftLottery.getRemainingQuantity());
                    gift.setConditionCount(giftLottery.getConditionCount());
                    break;
                }
            }
        }
        return gifts;
    }

    @Override
    public void giveLotteryGift(GiveLotteryGiftDTO dto) {
        UserTurntableNumber userTurntableNumber = userTurntableNumberService.getUserTurntableNumber(dto.getUserId(), dto.getType());
        userTurntableNumber.setNextWinGift(dto.getGiftId());
        userTurntableNumberService.updateById(userTurntableNumber);
    }




    public List<Gift> spendCoins(int coins,Integer type, Integer maxReward, Integer nextReward, Integer smallReward, Integer nextSmallReward, Integer smallestReward) {
        List<Integer> list = new ArrayList<>();

        if (maxReward != null){
            // 获得最大的奖励
            while (coins >= maxReward ) {
                list.add(maxReward);
                coins -= maxReward;
            }
        }

        if (nextReward != null){
            // 获得次大的奖励
            while (coins >= nextReward) {
                list.add(nextReward);
                coins -= nextReward;
            }
        }

        if (smallReward != null){
            // 获得最小的奖励
            while (coins >= smallReward) {
                list.add(smallReward);
                coins -= smallReward;
            }
        }


        if (nextSmallReward != null){
            // 获得最小的奖励
            while (coins >= nextSmallReward) {
                list.add(nextSmallReward);
                coins -= nextSmallReward;
            }
        }



        // 把剩余的硬币作为最小的奖励添加到列表中
        if (coins > 0 ) {
            for (int i = 0; i < coins / smallestReward; i++) {
                list.add(smallestReward);
            }
        }
        ArrayList<Gift> gifts = Lists.newArrayList();
        for (Integer price : list) {
            LambdaQueryWrapper<Gift> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(Gift::getPrice, price)
                    .eq(Gift::getType, type);
            Gift gift = this.getOne(wrapper);
            gift.setCount(1);
            gifts.add(gift);
        }

        return gifts;

    }

    private  GiftLotteryVO weightRandom(Map<GiftLotteryVO, Double> map) {
        //获取map里的key值集合
        List<GiftLotteryVO> weights = new ArrayList<>();
        for (Map.Entry<GiftLotteryVO, Double> entry : map.entrySet()) {
            GiftLotteryVO weightStr = entry.getKey();
            double fractionalWeight = entry.getValue();
            int integerWeight = (int) (fractionalWeight * WEIGHT_MULTIPLIER);

            for (int i = 0; i < integerWeight; i++) {
                weights.add(weightStr);
            }
        }

        // Randomly select an item from the weighted list
        int idx = new Random().nextInt(weights.size());
        return weights.get(idx);
    }


    private  WormholeLotteryVO weightRandomWormhole(Map<WormholeLotteryVO, Double> map) {
        //获取map里的key值集合
        List<WormholeLotteryVO> weights = new ArrayList<>();
        for (Map.Entry<WormholeLotteryVO, Double> entry : map.entrySet()) {
            WormholeLotteryVO weightStr = entry.getKey();
            double fractionalWeight = entry.getValue();
            int integerWeight = (int) (fractionalWeight * WEIGHT_MULTIPLIER);

            for (int i = 0; i < integerWeight; i++) {
                weights.add(weightStr);
            }
        }

        // Randomly select an item from the weighted list
        int idx = new Random().nextInt(weights.size());
        return weights.get(idx);
    }
}
